package com.ruoyi.sso.service.impl;

import com.ruoyi.common.core.exception.base.BaseException;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.sso.domain.AccessToken;
import com.ruoyi.sso.domain.AccessTokenContent;
import com.ruoyi.sso.domain.CodeContent;
import com.ruoyi.sso.domain.SsoUser;
import com.ruoyi.sso.other.constant.Oauth2Constant;
import com.ruoyi.sso.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @author weimingzhong
 * @date 2022/10/26 20:24
 * @remark
 */
@Service
public class Oauth2ServiceImpl implements IOauth2Service {

    @Autowired
    private CodeManager codeManager;
    @Autowired
    private AccessTokenManager accessTokenManager;
    @Autowired
    private RefreshTokenManager refreshTokenManager;
    @Autowired
    private TicketGrantingTicketManager ticketGrantingTicketManager;

    @Autowired
    private ICommonApplicationService commonApplicationService;


    /**
     * 获取accessToken
     *
     * @param appId
     * @param appKey
     * @param code
     *
     * @return
     */
    @Override
    @RequestMapping(value = "/access_token", method = RequestMethod.GET)
    public AccessToken getAccessToken(
            @RequestParam(value = Oauth2Constant.GRANT_TYPE) String grantType,
            @RequestParam(value = Oauth2Constant.APP_ID) String appId,
            @RequestParam(value = Oauth2Constant.APP_SECRET) String appKey,
            @RequestParam(value = Oauth2Constant.AUTH_CODE, required = false) String code,
            @RequestParam(value = Oauth2Constant.USERNAME, required = false) String username,
            @RequestParam(value = Oauth2Constant.PASSWORD, required = false) String password) {

        // APP密码模式,获取access_token,必须要有用户名和密码
        validateParam(grantType, code, username, password);
        // 校验应用
        if (!commonApplicationService.checkAppIdAndappKey(appId,appKey)) {
            throw new BaseException("appId错误或密钥错误");
        }
        // 校验授权
        AccessTokenContent accessTokenContent = validateAuth(grantType, code, username, password, appId);
        // 生成AccessToken返回
        return genereateAccessToken(accessTokenContent, null);
    }


    private void validateParam(String grantType, String code, String username, String password) {
        //授权模式为授权码模式
        if (StringUtils.equals(Oauth2Constant.AUTHORIZATION_CODE, grantType)) {
            if (StringUtils.isEmpty(code)) {
                throw new BaseException("授权码不能为空");
            }
            //授权模式为密码模式
        } else if (StringUtils.equals(Oauth2Constant.AUTHORIZATION_PASSWORD, grantType)) {
            if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
                throw new BaseException("username和password不能为空");
            } else {
                throw new BaseException("授权方式不支持");
            }
        }
    }

    private AccessTokenContent validateAuth(String grantType,
                                            String code,
                                            String username,
                                            String password,
                                            String appId) {
        AccessTokenContent authDto = null;
        //如果是授权码模式
        if (StringUtils.equals(Oauth2Constant.AUTHORIZATION_CODE, grantType)) {
            //使用code
            CodeContent codeContent = codeManager.getAndRemove(code);
            if (codeContent == null) {
                throw new BaseException("code有误或已过期");
            }
            //根据TGT，获取用户
            SsoUser user = ticketGrantingTicketManager.getAndRefresh(codeContent.getTgt());
            if (user == null) {
                throw new BaseException("服务端session已过期");
            }
            //创建token需要使用的用户
            authDto = new AccessTokenContent(codeContent, user, appId);
            //如果是密码模式
        } else if (StringUtils.equals(Oauth2Constant.AUTHORIZATION_PASSWORD, grantType)) {
            // app通过此方式由客户端代理转发http请求到服务端获取accessToken
//			Result<SsoUser> loginResult = userService.login(username, password);
//			if (!loginResult.isSuccess()) {
//				return Result.createError(loginResult.getMessage());
//			}
//			SsoUser user = loginResult.getData();
//			String tgt = ticketGrantingTicketManager.generate(loginResult.getData());
//			CodeContent codeContent = new CodeContent(tgt, false, null);
//			authDto = new AccessTokenContent(codeContent, user, appId);
        }
        return authDto;
    }

    /**
     * 刷新accessToken，并延长TGT超时时间
     * <p>
     * accessToken刷新结果有两种：
     * 1. 若accessToken已超时，那么进行refreshToken会生成一个新的accessToken，新的超时时间；
     * 2. 若accessToken未超时，那么进行refreshToken不会改变accessToken，但超时时间会刷新，相当于续期accessToken。
     *
     * @param appId
     * @param refreshToken
     * @return
     */
//	@RequestMapping(value = "/refresh_token", method = RequestMethod.GET)
//	public Result refreshToken(
//			@RequestParam(value = Oauth2Constant.APP_ID, required = true) String appId,
//			@RequestParam(value = Oauth2Constant.REFRESH_TOKEN, required = true) String refreshToken) {
//		if(!appService.exists(appId)) {
//			return Result.createError("非法应用");
//		}
//
//		RefreshTokenContent refreshTokenContent = refreshTokenManager.validate(refreshToken);
//		if (refreshTokenContent == null) {
//			return Result.createError("refreshToken有误或已过期");
//		}
//		AccessTokenContent accessTokenContent = refreshTokenContent.getAccessTokenContent();
//		if (!appId.equals(accessTokenContent.getAppId())) {
//			return Result.createError("非法应用");
//		}
//		SsoUser user = ticketGrantingTicketManager.getAndRefresh(accessTokenContent.getCodeContent().getTgt());
//		if (user == null) {
//			return Result.createError("服务端session已过期");
//		}
//
//		return Result.createSuccess(genereateRpcAccessToken(accessTokenContent, refreshTokenContent.getAccessToken()));
//	}

    private AccessToken genereateAccessToken(AccessTokenContent accessTokenContent, String accessToken) {
        String newAccessToken = accessToken;
        //如果accessToken为空
        if (newAccessToken == null || !accessTokenManager.refresh(newAccessToken)) {
            newAccessToken = accessTokenManager.generate(accessTokenContent);
        }

        String refreshToken = refreshTokenManager.generate(accessTokenContent, newAccessToken);

        return new AccessToken(newAccessToken, accessTokenManager.getExpiresIn(), refreshToken, accessTokenContent.getUser());
    }
}
